
import os
import wx

import ab_progress
import ab_ids as ai
import ab_plugins as ap

# Add the internal plug-ins below for initialization
import ab_i_atree

_REGISTEREDINTERNALLIST = (ab_i_atree,)


class AppLoad(wx.App):
    CATEGORY_PLUGIN_TYPE_BINARY = 0x01
    CATEGORY_PLUGIN_TYPE_SOURCE = 0x02

    def __init__(self, cf):
        self.cf = cf
        self.log = self.cf.readKey(ai.CfgParaLogObject)
        self.plx = self.cf.readKey(ai.CfgParaPlxObject)

        wx.App.__init__(self, 0)

    def OnInit(self):
        # use AppliMethod to initialize the progress bar
        self.frame = ab_progress.ProgressFrame(None, self, "Loading",
                                               self.process, True)
        self.frame.CenterOnScreen(wx.BOTH)
        self.frame.SetWindowStyleFlag(
            wx.RESIZE_BORDER | wx.RESIZE_BOX | wx.MAXIMIZE_BOX)
        self.frame.Show(True)
        self.SetTopWindow(self.frame)

        return True

    def debug(self, log):
        self.log.debug(log)

    def process(self, notify, *args, **kws):
        plxs = list()

        # load internal plug-ins
        plxs.extend(_REGISTEREDINTERNALLIST)

        # load directories
        ci = self.plx.getCategory()
        path = self.cf.readKey(ai.CfgParaPlxPath)
        if os.path.exists(path):
            for dirp in os.listdir(path):
                ppath = os.path.join(path, dirp)
                if not os.path.isdir(ppath):
                    continue

                category = ci.getCategoryWithPath(dirp)
                if category == ap.PlxTpBinaries:
                    # both .pyc and .pyo are supported
                    plxs += self.readPath(ppath,
                                          self.CATEGORY_PLUGIN_TYPE_BINARY)
                elif category != ap.PlxTpUnknown:
                    plxs += self.readPath(ppath,
                                          self.CATEGORY_PLUGIN_TYPE_SOURCE)

        # load extra
        for ppath in self.cf.readKey(ai.CfgParaExtraPlx) or list():
            plxs += self.readPath(ppath,
                                  self.CATEGORY_PLUGIN_TYPE_BINARY |
                                  self.CATEGORY_PLUGIN_TYPE_SOURCE)

        step = 0
        # load plug-ins
        for plx in plxs:
            notify(100 * step / len(plxs), 'loading %s ...' % plx)
            if isinstance(plx, (str, unicode)):
                ret, names = self.plx.installFile(plx)
            else:
                ret, names = self.plx.installModule(plx)

            if ret:
                notify(step, 'load %s successfully' % plx)
                if isinstance(plx, (str, unicode)):
                    self.log.debug("Install External %s" % plx)
                else:
                    self.log.debug("Install Internal %s" % plx)

                for name in names:
                    self.log.debug("  Instances: %s" % name)
            else:
                self.log.error("Failed for Internal '%s'" % plx)
                notify(step, 'failed to load %s' % plx)

    def readPath(self, path, filetype):
        ext_list = list()

        if filetype & self.CATEGORY_PLUGIN_TYPE_SOURCE:
            ext_list.append('.py')
        if filetype & self.CATEGORY_PLUGIN_TYPE_BINARY:
            ext_list.extend(('.pyc', '.pyo'))

        def filter_fun(x):
            return (os.path.splitext(x))[1] in ext_list

        added = list()
        files = list()

        try:
            li = filter(filter_fun, os.listdir(path))
            # don't load both binaries and sources to avoid override,
            # for example, foo.py and foo.pyc or foo.pyo
            for f in li:
                main = (os.path.splitext(f))[0]
                if main not in added:
                    files.append(os.path.join(path, f))
                    added.append(main)
        finally:
            return files
